<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title> LveRecordJs优化</title>
  </head>
  <body>
    <input type="file" id="fileInput" />
    <canvas
      id="myCanvas"
      width="400"
      height="400"
      style="border: 1px solid #000"
    ></canvas>
    <script>
      // 获取文件输入框和 Canvas 元素
      const fileInput = document.getElementById("fileInput");
      const canvas = document.getElementById("myCanvas");
      const ctx = canvas.getContext("2d");
      // 当用户选择文件时执行
      fileInput.addEventListener("change", function (event) {
        const file = event.target.files[0];
        const reader = new FileReader();
        // 读取文件并将其转换为图像
        reader.onload = function (readerEvent) {
          const image = new Image();
          image.onload = function () {
            const virtualCanvas = document.createElement("canvas");
            const virtualCtx = virtualCanvas.getContext("2d");
            virtualCanvas.width = 400;
            virtualCanvas.height = 400;
            // 清除 Canvas
            virtualCtx.clearRect(0, 0, canvas.width, canvas.height);
            // 计算缩放比例，以确保图片适应 Canvas 大小
            const scaleFactor = Math.min(
              canvas.width / image.width,
              canvas.height / image.height
            );
            const scaledWidth = image.width * scaleFactor;
            const scaledHeight = image.height * scaleFactor;
            // 绘制图片
            virtualCtx.drawImage(image, 0, 0, scaledWidth, scaledHeight);
            // 获取图片的像素数据
            const imageData = virtualCtx.getImageData(
              0,
              0,
              canvas.width,
              canvas.height
            );
            const data = imageData.data;
            const nums = data.length / 4;
            const result = [];
            // 一笔一笔地绘制图片
            for (let i = 0; i < data.length; i += 4) {
              const x = (i / 4) % canvas.width;
              const y = Math.floor(i / 4 / canvas.width);

              // 获取像素的 RGBA 值
              const red = data[i];
              const green = data[i + 1];
              const blue = data[i + 2];
              const alpha = data[i + 3];
              result.push({
                fillStyle:
                  "rgba(" +
                  red +
                  ", " +
                  green +
                  ", " +
                  blue +
                  ", " +
                  alpha / 255 +
                  ")",
                fillRect: [x, y, 1, 1],
              });
            }
            const finalResult = convertTo2DArray(result, 100);
            generate(ctx, finalResult);
          };
          image.src = readerEvent.target.result;
        };

        if (file) {
          reader.readAsDataURL(file);
        }
      });
      const convertTo2DArray = (arr, colCount) => {
        const rowCount = Math.ceil(arr.length / colCount); // 计算行数
        const result = [];
        for (let i = 0; i < rowCount; i++) {
          const row = [];
          for (let j = 0; j < colCount; j++) {
            let index = i * colCount + j;
            if (index < arr.length) {
              row.push(arr[index]);
            } else {
              break;
            }
          }
          result.push(row);
        }
        return result;
      };

      /**
       * 生成器初始化
       **/
      const generate = (ctx, arr) => {
        function* gen(list) {
          for (const item of list) {
            yield asyncThunk(ctx, item);
          }
        }
        this.g = gen(arr);
        let res = this.g.next();
        let promise = res.value;
        let done = res.done;
        const fn = () => {
          if (done) {
            return Promise.resolve(promise);
          }
          promise.then((data) => {
            // done为true，promise是 生成器函数的返回值。注意这里的next参数才是上面data2的赋值
            res = this.g.next(data);
            promise = res.value;
            done = res.done;
            // 继续往前走
            fn();
          });
        };
        fn();
      };
      /**
       * 异步子逻辑执行，所有单个操作都在此处
       **/
      const asyncThunk = (ctx, item) => {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            for (const item1 of item) {
              ctx.fillStyle = item1.fillStyle;
              ctx.fillRect(...item1.fillRect);
            }
            resolve(true);
          }, 1);
        });
      };
    </script>
  </body>
</html>


